package multithread.waitandnotify;

/**
 * 这里主要是，通知提前执行了，然后在去执行c.wait 就会导致假死的。
 * 主要加了标记，isSignalled 为true,代表计算器先执行了，后面不需要等待了
 *
 */
public class WaitAndNotifyTest2 {
    static  class Calculator extends Thread {
        int total;
        boolean isSignalled = false;
        @Override
        public void run() {
            System.out.println("323232323");
            synchronized (this){
                isSignalled = true;
                for(int i = 0; i < 101; i++){
                    total += i;
                }
                this.notify();
            }
            System.out.println("fff");
        }
    }

     static class ReaderResult extends Thread {
         Calculator c;

         public ReaderResult(Calculator c) {
             this.c = c;
         }

         @Override
         public void run() {
             synchronized (c) {
                 //如果没有更新就一直等待，知道那边的通知到了就走下面的。
                 //如果那边的线程先走了，那么让那边直接通知，这边的c.wait就不要走了
                 //代表已经走了前面的notify,这里不需要阻塞了。
                 if(!c.isSignalled){
                     try {
                         System.out.println(Thread.currentThread() + "等待计算结...");
                         c.wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
                 System.out.println(Thread.currentThread() + "计算结果为:" + c.total);
             }
         }
     }

    /**
     * 一直死循环：Thread[Thread-1,5,main]等待计算结...
     *
     *可以看出ReaderResult在Calculator上等待。发生这个现象就是常说的通知丢失，在获取通知前，通知提前到达，我们先计算结果，计算完后再通知，
     * 但是这个时候获取结果没有在等待通知，等到获取结果的线程想获取结果时，这个通知已经通知过了，
     * 所以就发生丢失，那我们该如何避免?可以设置变量表示是否被通知过，修改代码如下：
     * 改造参考WaitNotifyTest2
     */
    public static void testNotifyFirstRun(){
        Calculator calculator = new Calculator();
        calculator.start();

//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        //先启动获取计算结果线程
        new ReaderResult(calculator).start();

    }

    public static void main(String[] args) {
        testNotifyFirstRun();
    }
}
